A typical computer system includes a microprocessor for executing applications software and other code stored in a memory of the computer system. When an interrupt occurs during software execution, the microprocessor must suspend execution of the code it is presently executing, save its place, and search a table stored in memory that lists "interrupt vectors." Each interrupt vector is a pointer that indicates to the microprocessor the location in memory of code for servicing the interrupt, known as the "interrupt handler." The microprocessor reads the value of the associated vector and begins executing the code stored at the memory location indicated by the vector. However, prior to doing so, the computer system hardware and/or the interrupt handler typically save the state, or "context," of the microprocessor registers, which will be destroyed by the interrupt handler if the interrupt handler makes use of those registers. Before the microprocessor resumes execution of the interrupted code, the interrupt handler and/or the system hardware restore the saved registers. As saving and restoring the context of a microprocessor is well known in the art, the specifics of these operations are not further described in greater detail herein.
Saving the state, or context, of the microprocessor upon the occurrence of an interrupt increases interrupt latency, which is defined as the amount of time that elapses between the time the microprocessor takes the interrupt and begins to execute the interrupt processing code. Interrupt processing code is that part of the interrupt handler that is not related to register saving and restoration. To increase system speed, it is highly desirable to reduce interrupt latency, as well as register restoration time at the completion of the interrupt processing code. Reducing interrupt latency and register restoration time is particularly important where interrupt handlers are executed with interrupts disabled, as other interrupts may be missed during execution of the interrupt handler.
The Am29K family of embedded products, designed and manufactured by Advanced Micro Devices (AMD) of Sunnyvale, Calif., comprises a growing group of 32-bit reduced-instruction set (RISC) microprocessors (hereinafter "29K microprocessors"). 29K microprocessors employ submicron circuits to increase the degree of system integration, yielding very low system cost. Dense circuitry and a large number of on-chip peripherals, such as an on-chip timer, minimize the number of components required to implement embedded systems, while providing performance superior to that of complex-instruction-set (CISC) microprocessors.
Embedded code application developers are typically required to deal with interrupts from peripheral devices requiring attention. Compared to CISC microprocessors, which typically do not have a register stack, interrupt handling is slightly more difficult to achieve with microprocessors, such as 29K microprocessors, that do have a register stack that must be considered when handling interrupts. In addition, such microprocessors typically do not have microcode to save automatically their interrupted context, or state, to enable the microprocessor to continue execution from the point at which the interrupt occurred upon completion of the associated interrupt handler.
As described at section 16.2 through 16.4 of the "Am29200.TM. and Am29205.TM. RISC Microcontrollers User's Manual, Rev. 1, 1994," published by AMD (hereinafter "User's Manual") and herein incorporated by reference in its entirety, 29K microprocessors include a number of protected special purpose registers. One such register is the Current Processor Status (CPS) register, which controls the behavior of the microprocessor and its ability to recognize exceptional events. The CPS register includes a bit known as the Freeze (FZ) bit that, when set, prevents certain critical registers from being updated during interrupt processing, except by explicit data movement. The FZ bit is set whenever an interrupt is taken, holding the critical state, or context, of the microprocessor so that it cannot be unintentionally modified by the interrupt handler. Setting the FZ bit places the microprocessor in "Freeze mode." Section 16.4 of the User's Manual describes in detail typical interrupt trap handling using the FZ bit.
When writing interrupt handlers for microprocessors, most code developers prefer to use C language, rather than assembly language, for obvious reasons, and various methods are known to in the art for associating C language interrupt handler with a 29K microprocessor interrupt. For example, as described in an article by Daniel Mann entitled "A Short Cut: C Language Interrupt Handlers," published in Fusion29K NEWS, Issue 13 (March 1993) (hereinafter "Mann article"), which is herein incorporated by reference in its entirety, a special code segment, referred to as "trampoline code," is included in the library code supplied with 29K microprocessors for connecting a Freeze mode interrupt handler with the required C level code. The trampoline code is called by the Freeze mode interrupt handler after C level context of the microprocessor has been prepared. As used herein "preparing" or "saving" C level context constitutes saving the contents of critical registers on the memory stack and preparing the register stack for further use by the interrupt handler, as interrupts may occur at times when the condition of the register stack is such that it is not immediately usable by a C language handler. "Restoring" C level context is the reverse of this process. In general, C level context must have been prepared in response to each interrupt to save the state of the microprocessor at the time the interrupt occurs so that, once the interrupt has been serviced (i.e., the interrupt handler has completed execution), the microprocessor can continue executing instructions from the point at which it was interrupted. As further described in detail below, preparing C level context can be extremely time consuming, especially where multiple nested interrupts must be processed.
FIG. 1 is a timing diagram illustrating a typical prior art method implemented by a microprocessor, such as a 29K microprocessor, for handling multiple nested interrupts using C language interrupt handlers. Prior to time T1, the microprocessor is executing a MAIN code segment, or program, 100a, 100b. At time T1, after only a first portion 100a of the MAIN code segment 100a, 100b has been executed, a first interrupt I1 occurs. Responsive to I1, the microprocessor is placed in Freeze mode, that is, the FZ bit of the CPS register is set and C level context is prepared. Preparing C level context involves pushing all critical registers onto the memory stack to save the state of the microprocessor at time T1 and preparing the register stack for use by C language, or C level, interrupt handler code associated with I1, designated by reference numerals 102a, 102b. Typically, as much as 40-70 microseconds (.mu.s) may be spent in preparing C level context before the interrupt processing code of a C language interrupt handler, such as the I1 interrupt handler 102a, 102b, may begin execution. Referring again to FIG. 1, after C level context is prepared at time T1, the I1 interrupt handler 102a, 102b begins execution. At time T2, after only a first portion 102a of the I1 interrupt handler 102a, 102b has been executed, a second interrupt I2 occurs. Responsive to I2, the microprocessor is again placed in Freeze mode and C level context must again be prepared, so that the unexecuted portion 102b of the I1 handler 102a, 102b may be executed upon completion of an interrupt handler associated with I2, designated by reference numerals 104a, 104b.
At this point, the I2 interrupt handler 104a, 104b begins execution. At time T3, after only a portion 104a of the I2 handler 104a, 104b has been executed, a third interrupt I3 occurs. Responsive to I3, the microprocessor is again placed in Freeze mode and C level context of the microprocessor must once again be prepared, so that the unexecuted portion 104b of the I2 interrupt handler 104a, 104b may be executed upon completion of an interrupt handler associated with I3, designated by the reference numeral 106. At time T4, execution of the I3 handler 106 is complete and the C level context previously saved at time T3 is restored. At this point, the remaining portion 104b of the I2 handler 104a, 104b is executed. At time T5, execution of the I2 handler 104a, 104b is complete and the context previously saved at time T2 is restored. At this point, the remaining portion of the I1 handler 102a, 102b is executed. At time T6, execution of the I1 handler 102a, 102b is complete, the context saved at time T1 is returned, and the microprocessor resumes execution of the unexecuted portion 100b of the MAIN code segment 100a, 100b. As a result, the interrupts are completed in the reverse order in which they were received.
It should be understood that, although only three nested interrupts are shown in FIG. 1, any number of nested interrupts could occur, each requiring C level context to be saved and restored before and after execution of the associated interrupt handler. Assuming, as is typically the case, that the amount of time needed to restore C level context is equal to that needed to prepare same (i.e., 40-70 .mu.s), it is apparent that for each interrupt serviced by a C language interrupt handler, m approximately 80-140 .mu.s will be expended in simply preparing for and returning from the interrupt. Clearly, the greater the number iof nested interrupts expected, the greater the cost, in terms of clock cycles, of preparing C level context for interrupt processing and the greater the benefit to be realized in avoiding such nested interrupts. In addition, interrupt latency will alwayx be at least 40-70 .mu.s, i.e., the time required to prepare C level context.
Accordingly, what is needed is a method of processing multpile nested interrupts using C leanguage handlers which substantially reduces interrupt latency and increases the speed with which multiple nested interrupts may be processed.